From d258a20a06feb0d65dc4b01b88c5cc5449c5d606 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Sun, 5 Apr 2020 16:31:23 -0600 Subject: [PATCH] Optimize QString usage in gpx format. (#530) Don't convert QStringRef to QString unecessarily. Use QLatin1String, QStringLiteral. A 18% performance improvement has been measured with gpxbabel -f lowrance-v4.gpx -o lowranceusr,wversion=4 -F lowrance-v4.usr valgrind --tool=callgrind was useful. Further improvements in the reader are likely to be found in xml_parse_time. --- gpx.cc | 93 ++++++++++++++++++++++++++++------------------------------ gpx.h | 10 +++---- 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/gpx.cc b/gpx.cc index 108475425..bb10603aa 100644 --- a/gpx.cc +++ b/gpx.cc @@ -28,6 +28,7 @@ #include // for QDateTime #include // for QHash #include // for QIODevice, operator|, QIODevice::ReadOnly, QIODevice::Text, QIODevice::WriteOnly +#include // for QLatin1Char #include // for QLatin1String #include // for QStaticStringData #include // for QString, QStringLiteral, operator+, operator== @@ -133,11 +134,11 @@ GpxFormat::get_tag(const QString& t) const void GpxFormat::tag_gpx(const QXmlStreamAttributes& attr) { - if (attr.hasAttribute("version")) { + if (attr.hasAttribute(QLatin1String("version"))) { /* Set the default output version to the highest input * version. */ - QVersionNumber thisVersion = QVersionNumber::fromString(attr.value("version").toString()).normalized(); + QVersionNumber thisVersion = QVersionNumber::fromString(attr.value(QLatin1String("version")).toString()).normalized(); if (gpx_highest_version_read.isNull()) { gpx_highest_version_read = thisVersion; } else if (!thisVersion.isNull() && (gpx_highest_version_read < thisVersion)) { @@ -167,11 +168,11 @@ GpxFormat::tag_wpt(const QXmlStreamAttributes& attr) link_ = new UrlLink; cur_tag = nullptr; - if (attr.hasAttribute("lat")) { - wpt_tmp->latitude = attr.value("lat").toString().toDouble(); + if (attr.hasAttribute(QLatin1String("lat"))) { + wpt_tmp->latitude = attr.value(QLatin1String("lat")).toDouble(); } - if (attr.hasAttribute("lon")) { - wpt_tmp->longitude = attr.value("lon").toString().toDouble(); + if (attr.hasAttribute(QLatin1String("lon"))) { + wpt_tmp->longitude = attr.value(QLatin1String("lon")).toDouble(); } fs_ptr = &wpt_tmp->fs; } @@ -180,8 +181,8 @@ void GpxFormat::tag_cache_desc(const QXmlStreamAttributes& attr) { cache_descr_is_html = false; - if (attr.hasAttribute("html")) { - if (attr.value("html").compare(QLatin1String("True")) == 0) { + if (attr.hasAttribute(QLatin1String("html"))) { + if (attr.value(QLatin1String("html")).compare(QLatin1String("True")) == 0) { cache_descr_is_html = true; } } @@ -192,34 +193,34 @@ GpxFormat::tag_gs_cache(const QXmlStreamAttributes& attr) const { geocache_data* gc_data = wpt_tmp->AllocGCData(); - if (attr.hasAttribute("id")) { - gc_data->id = attr.value("id").toString().toLongLong(); + if (attr.hasAttribute(QLatin1String("id"))) { + gc_data->id = attr.value(QLatin1String(QLatin1String("id"))).toLongLong(); } - if (attr.hasAttribute("available")) { - if (attr.value("available").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) { + if (attr.hasAttribute(QLatin1String("available"))) { + if (attr.value(QLatin1String("available")).compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) { gc_data->is_available = status_true; - } else if (attr.value("available").compare(QLatin1String("False"), Qt::CaseInsensitive) == 0) { + } else if (attr.value(QLatin1String("available")).compare(QLatin1String("False"), Qt::CaseInsensitive) == 0) { gc_data->is_available = status_false; } } - if (attr.hasAttribute("archived")) { - if (attr.value("archived").compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) { + if (attr.hasAttribute(QLatin1String("archived"))) { + if (attr.value(QLatin1String("archived")).compare(QLatin1String("True"), Qt::CaseInsensitive) == 0) { gc_data->is_archived = status_true; - } else if (attr.value("archived").compare(QLatin1String("False"), Qt::CaseInsensitive) == 0) { + } else if (attr.value(QLatin1String("archived")).compare(QLatin1String("False"), Qt::CaseInsensitive) == 0) { gc_data->is_archived = status_false; } } } void -GpxFormat::start_something_else(const QString& el, const QXmlStreamAttributes& attr) +GpxFormat::start_something_else(const QStringRef& el, const QXmlStreamAttributes& attr) { if (!fs_ptr) { return; } auto* new_tag = new xml_tag; - new_tag->tagname = el; + new_tag->tagname = el.toString(); const QXmlStreamNamespaceDeclarations ns = reader->namespaceDeclarations(); new_tag->attributes.reserve(attr.size() + ns.size()); @@ -286,11 +287,11 @@ GpxFormat::tag_log_wpt(const QXmlStreamAttributes& attr) const auto* lwp_tmp = new Waypoint; /* extract the lat/lon attributes */ - if (attr.hasAttribute("lat")) { - lwp_tmp->latitude = attr.value("lat").toString().toDouble(); + if (attr.hasAttribute(QLatin1String("lat"))) { + lwp_tmp->latitude = attr.value(QLatin1String("lat")).toDouble(); } - if (attr.hasAttribute("lon")) { - lwp_tmp->longitude = attr.value("lon").toString().toDouble(); + if (attr.hasAttribute(QLatin1String("lon"))) { + lwp_tmp->longitude = attr.value(QLatin1String("lon")).toDouble(); } /* Make a new shortname. Since this is a groundspeak extension, we assume that GCBLAH is the current shortname format and that @@ -307,7 +308,7 @@ GpxFormat::tag_log_wpt(const QXmlStreamAttributes& attr) const } void -GpxFormat::gpx_start(const QString& el, const QXmlStreamAttributes& attr) +GpxFormat::gpx_start(const QStringRef& el, const QXmlStreamAttributes& attr) { /* * Reset end-of-string without actually emptying/reallocing cdatastr. @@ -320,16 +321,16 @@ GpxFormat::gpx_start(const QString& el, const QXmlStreamAttributes& attr) tag_gpx(attr); break; case tt_link: - if (attr.hasAttribute("href")) { - link_url = attr.value("href").toString(); + if (attr.hasAttribute(QLatin1String("href"))) { + link_url = attr.value(QLatin1String("href")).toString(); } break; case tt_wpt: tag_wpt(attr); break; case tt_wpttype_link: - if (attr.hasAttribute("href")) { - link_url = attr.value("href").toString(); + if (attr.hasAttribute(QLatin1String("href"))) { + link_url = attr.value(QLatin1String("href")).toString(); } break; case tt_rte: @@ -356,8 +357,8 @@ GpxFormat::gpx_start(const QString& el, const QXmlStreamAttributes& attr) break; case tt_rte_link: case tt_trk_link: - if (attr.hasAttribute("href")) { - link_url = attr.value("href").toString(); + if (attr.hasAttribute(QLatin1String("href"))) { + link_url = attr.value(QLatin1String("href")).toString(); } break; case tt_unknown: @@ -376,8 +377,8 @@ GpxFormat::gpx_start(const QString& el, const QXmlStreamAttributes& attr) tag_cache_desc(attr); break; case tt_cache_placer: - if (attr.hasAttribute("id")) { - wpt_tmp->AllocGCData()->placer_id = attr.value("id").toString().toInt(); + if (attr.hasAttribute(QLatin1String("id"))) { + wpt_tmp->AllocGCData()->placer_id = attr.value(QLatin1String("id")).toInt(); } default: break; @@ -550,7 +551,7 @@ xml_parse_time(const QString& dateTimeString) } void -GpxFormat::gpx_end(const QString& /*unused*/) +GpxFormat::gpx_end(const QStringRef& /*unused*/) { static QDateTime gc_log_date; @@ -890,7 +891,7 @@ GpxFormat::gpx_end(const QString& /*unused*/) void -GpxFormat::gpx_cdata(const QString& s) +GpxFormat::gpx_cdata(const QStringRef& s) { QString* cdata; cdatastr += s; @@ -1004,15 +1005,15 @@ GpxFormat::wr_init(const QString& fname) writer->writeStartElement(QStringLiteral("metadata")); } if (gpx_global) { - gpx_write_gdata(gpx_global->name, "name"); - gpx_write_gdata(gpx_global->desc, "desc"); + gpx_write_gdata(gpx_global->name, QStringLiteral("name")); + gpx_write_gdata(gpx_global->desc, QStringLiteral("desc")); } /* In GPX 1.1, author changed from a string to a PersonType. * since it's optional, we just drop it instead of rewriting it. */ if (gpx_write_version < gpx_1_1) { if (gpx_global) { - gpx_write_gdata(gpx_global->author, "author"); + gpx_write_gdata(gpx_global->author, QStringLiteral("author")); } } // else { // TODO: gpx 1.1 author goes here. @@ -1020,9 +1021,9 @@ GpxFormat::wr_init(const QString& fname) /* In GPX 1.1 email, url, urlname aren't allowed. */ if (gpx_write_version < gpx_1_1) { if (gpx_global) { - gpx_write_gdata(gpx_global->email, "email"); - gpx_write_gdata(gpx_global->url, "url"); - gpx_write_gdata(gpx_global->urlname, "urlname"); + gpx_write_gdata(gpx_global->email, QStringLiteral("email")); + gpx_write_gdata(gpx_global->url, QStringLiteral("url")); + gpx_write_gdata(gpx_global->urlname, QStringLiteral("urlname")); } } else { if (gpx_global) { @@ -1041,7 +1042,7 @@ GpxFormat::wr_init(const QString& fname) writer->writeTextElement(QStringLiteral("time"), now.toPrettyString()); if (gpx_global) { - gpx_write_gdata(gpx_global->keywords, "keywords"); + gpx_write_gdata(gpx_global->keywords, QStringLiteral("keywords")); } gpx_write_bounds(); @@ -1075,17 +1076,13 @@ GpxFormat::read() // do processing switch (reader->tokenType()) { case QXmlStreamReader::StartElement: - current_tag.append("/"); + current_tag.append(QLatin1Char('/')); current_tag.append(reader->qualifiedName()); - - { - const QXmlStreamAttributes attrs = reader->attributes(); - gpx_start(reader->qualifiedName().toString(), attrs); - } + gpx_start(reader->qualifiedName(), reader->attributes()); break; case QXmlStreamReader::EndElement: - gpx_end(reader->qualifiedName().toString()); + gpx_end(reader->qualifiedName()); current_tag.chop(reader->qualifiedName().length() + 1); cdatastr.clear(); break; @@ -1094,7 +1091,7 @@ GpxFormat::read() // It is tempting to skip this if reader->isWhitespace(). // That would lose all whitespace element values if the exist, // but it would skip line endings and indentation that doesn't matter. - gpx_cdata(reader->text().toString()); + gpx_cdata(reader->text()); break; // On windows with input redirection we can read an Invalid token diff --git a/gpx.h b/gpx.h index f1b15685d..1500d7eae 100644 --- a/gpx.h +++ b/gpx.h @@ -22,9 +22,9 @@ #define GPX_H_INCLUDED_ #include // for QHash -#include // for QList #include // for QString #include // for QStringList +#include // for QStringRef #include // for QVector #include // for QVersionNumber #include // for QXmlStreamAttributes @@ -202,12 +202,12 @@ private: void tag_wpt(const QXmlStreamAttributes& attr); void tag_cache_desc(const QXmlStreamAttributes& attr); void tag_gs_cache(const QXmlStreamAttributes& attr) const; - void start_something_else(const QString& el, const QXmlStreamAttributes& attr); + void start_something_else(const QStringRef& el, const QXmlStreamAttributes& attr); void end_something_else(); void tag_log_wpt(const QXmlStreamAttributes& attr) const; - void gpx_start(const QString& el, const QXmlStreamAttributes& attr); - void gpx_end(const QString& unused); - void gpx_cdata(const QString& s); + void gpx_start(const QStringRef& el, const QXmlStreamAttributes& attr); + void gpx_end(const QStringRef& unused); + void gpx_cdata(const QStringRef& s); void write_attributes(const QXmlStreamAttributes& attributes) const; void fprint_xml_chain(xml_tag* tag, const Waypoint* wpt) const; void write_gpx_url(const UrlList& urls) const; -- 2.30.2